From ddade6649613be5442af39b632f0277220bd6fa3 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 12 Nov 2013 12:03:50 +0100 Subject: [PATCH] broadway: use 'click-to-focus' approach instead of 'focus-follows-mouse' The broadway backend would move the focus from one window to another based on where the mouse was (i.e. 'focus-follows-mouse' approach). Handling the focus this wait didn't play well with widgets which rely on focus-in-event and focus-out-event, like the GtkEntry when using a completion popup window, see e.g: https://bugzilla.gnome.org/show_bug.cgi?id=708984 So instead, setup broadway to require a click in a window to move the focus (i.e. 'click-to-focus' approach): * The implicit GDK_FOCUS_CHANGE events that were generated upon reception of BROADWAY_EVENT_ENTER or BROADWAY_EVENT_LEAVE are removed. * The broadway daemon will now keep track of which is the focused window * Whenever the daemon detects an incoming BROADWAY_EVENT_BUTTON_PRESS, it will trigger the focused window switch, which sends a new BROADWAY_EVENT_FOCUS to the client, specifying which windows holds the focus. * Upon reception of a BROADWAY_EVENT_FOCUS, the client will generate a new GDK_FOCUS_CHANGE. * gdk_broadway_window_focus() was also implemented, which now requests the focus to the broadway server using a new BROADWAY_REQUEST_FOCUS_WINDOW. This is based on an initial patch from Aleksander Morgado . --- gdk/broadway/broadway-protocol.h | 15 ++++++++++++--- gdk/broadway/broadway-server.c | 25 +++++++++++++++++++++++++ gdk/broadway/broadway-server.h | 2 ++ gdk/broadway/broadwayd.c | 5 +++++ gdk/broadway/gdkbroadway-server.c | 11 +++++++++++ gdk/broadway/gdkbroadway-server.h | 2 ++ gdk/broadway/gdkeventsource.c | 29 +++++++++++++---------------- gdk/broadway/gdkwindow-broadway.c | 13 +++++++++++++ 8 files changed, 83 insertions(+), 19 deletions(-) diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h index 7c25f8ccfe..d42625f077 100644 --- a/gdk/broadway/broadway-protocol.h +++ b/gdk/broadway/broadway-protocol.h @@ -21,7 +21,8 @@ typedef enum { BROADWAY_EVENT_UNGRAB_NOTIFY = 'u', BROADWAY_EVENT_CONFIGURE_NOTIFY = 'w', BROADWAY_EVENT_DELETE_NOTIFY = 'W', - BROADWAY_EVENT_SCREEN_SIZE_CHANGED = 'd' + BROADWAY_EVENT_SCREEN_SIZE_CHANGED = 'd', + BROADWAY_EVENT_FOCUS = 'f' } BroadwayEventType; typedef enum { @@ -104,6 +105,11 @@ typedef struct { gint32 id; } BroadwayInputDeleteNotify; +typedef struct { + BroadwayInputBaseMsg base; + gint32 id; +} BroadwayInputFocusMsg; + typedef union { BroadwayInputBaseMsg base; BroadwayInputPointerMsg pointer; @@ -115,6 +121,7 @@ typedef union { BroadwayInputConfigureNotify configure_notify; BroadwayInputDeleteNotify delete_notify; BroadwayInputScreenResizeNotify screen_resize_notify; + BroadwayInputFocusMsg focus; } BroadwayInputMsg; typedef enum { @@ -129,7 +136,8 @@ typedef enum { BROADWAY_REQUEST_UPDATE, BROADWAY_REQUEST_MOVE_RESIZE, BROADWAY_REQUEST_GRAB_POINTER, - BROADWAY_REQUEST_UNGRAB_POINTER + BROADWAY_REQUEST_UNGRAB_POINTER, + BROADWAY_REQUEST_FOCUS_WINDOW } BroadwayRequestType; typedef struct { @@ -141,7 +149,7 @@ typedef struct { typedef struct { BroadwayRequestBase base; guint32 id; -} BroadwayRequestDestroyWindow, BroadwayRequestShowWindow, BroadwayRequestHideWindow; +} BroadwayRequestDestroyWindow, BroadwayRequestShowWindow, BroadwayRequestHideWindow, BroadwayRequestFocusWindow; typedef struct { BroadwayRequestBase base; @@ -213,6 +221,7 @@ typedef union { BroadwayRequestGrabPointer grab_pointer; BroadwayRequestUngrabPointer ungrab_pointer; BroadwayRequestTranslate translate; + BroadwayRequestFocusWindow focus_window; } BroadwayRequest; typedef enum { diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c index c3ebef633a..ae88cce40f 100644 --- a/gdk/broadway/broadway-server.c +++ b/gdk/broadway/broadway-server.c @@ -54,6 +54,7 @@ struct _BroadwayServer { GHashTable *id_ht; GList *toplevels; BroadwayWindow *root; + gint32 focused_window_id; /* -1 => none */ guint32 screen_width; guint32 screen_height; @@ -215,6 +216,10 @@ update_event_state (BroadwayServer *server, break; case BROADWAY_EVENT_BUTTON_PRESS: case BROADWAY_EVENT_BUTTON_RELEASE: + if (message->base.type == BROADWAY_EVENT_BUTTON_PRESS && + server->focused_window_id != message->pointer.mouse_window_id) + broadway_server_focus_window (server, message->pointer.mouse_window_id); + server->last_x = message->pointer.root_x; server->last_y = message->pointer.root_y; server->last_state = message->pointer.state; @@ -1460,6 +1465,26 @@ broadway_server_window_move_resize (BroadwayServer *server, return sent; } +void +broadway_server_focus_window (BroadwayServer *server, + gint new_focused_window) +{ + BroadwayInputMsg focus_msg; + + if (server->focused_window_id == new_focused_window) + return; + + /* Keep track of the new focused window */ + server->focused_window_id = new_focused_window; + + memset (&focus_msg, 0, sizeof (focus_msg)); + focus_msg.base.type = BROADWAY_EVENT_FOCUS; + focus_msg.base.time = broadway_server_get_last_seen_time (server); + focus_msg.focus.id = new_focused_window; + + broadway_events_got_input (&focus_msg, -1); +} + guint32 broadway_server_grab_pointer (BroadwayServer *server, gint client_id, diff --git a/gdk/broadway/broadway-server.h b/gdk/broadway/broadway-server.h index 7941bcdd56..e5a3718bea 100644 --- a/gdk/broadway/broadway-server.h +++ b/gdk/broadway/broadway-server.h @@ -78,6 +78,8 @@ gboolean broadway_server_window_move_resize (BroadwayServer * int y, int width, int height); +void broadway_server_focus_window (BroadwayServer *server, + gint new_focused_window); cairo_surface_t * broadway_server_open_surface (BroadwayServer *server, guint32 id, char *name, diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index eb98528524..8c24a4f85a 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -294,6 +294,9 @@ client_handle_request (BroadwayClient *client, send_reply (client, request, (BroadwayReply *)&reply_ungrab_pointer, sizeof (reply_ungrab_pointer), BROADWAY_REPLY_UNGRAB_POINTER); break; + case BROADWAY_REQUEST_FOCUS_WINDOW: + broadway_server_focus_window (server, request->focus_window.id); + break; default: g_warning ("Unknown request of type %d\n", request->base.type); } @@ -537,6 +540,8 @@ get_event_size (int type) return sizeof (BroadwayInputDeleteNotify); case BROADWAY_EVENT_SCREEN_SIZE_CHANGED: return sizeof (BroadwayInputScreenResizeNotify); + case BROADWAY_EVENT_FOCUS: + return sizeof (BroadwayInputFocusMsg); default: g_assert_not_reached (); } diff --git a/gdk/broadway/gdkbroadway-server.c b/gdk/broadway/gdkbroadway-server.c index 0324764b5f..d85cfa522c 100644 --- a/gdk/broadway/gdkbroadway-server.c +++ b/gdk/broadway/gdkbroadway-server.c @@ -497,6 +497,17 @@ _gdk_broadway_server_window_hide (GdkBroadwayServer *server, return TRUE; } +void +_gdk_broadway_server_window_focus (GdkBroadwayServer *server, + gint id) +{ + BroadwayRequestFocusWindow msg; + + msg.id = id; + gdk_broadway_server_send_message (server, msg, + BROADWAY_REQUEST_FOCUS_WINDOW); +} + void _gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server, gint id, gint parent) diff --git a/gdk/broadway/gdkbroadway-server.h b/gdk/broadway/gdkbroadway-server.h index 2b93a85ad3..0ddf39e349 100644 --- a/gdk/broadway/gdkbroadway-server.h +++ b/gdk/broadway/gdkbroadway-server.h @@ -47,6 +47,8 @@ gboolean _gdk_broadway_server_window_show (GdkBroadwaySer gint id); gboolean _gdk_broadway_server_window_hide (GdkBroadwayServer *server, gint id); +void _gdk_broadway_server_window_focus (GdkBroadwayServer *server, + gint id); void _gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server, gint id, gint parent); diff --git a/gdk/broadway/gdkeventsource.c b/gdk/broadway/gdkeventsource.c index d7cdede0a4..5330d6b123 100644 --- a/gdk/broadway/gdkeventsource.c +++ b/gdk/broadway/gdkeventsource.c @@ -117,14 +117,6 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message) node = _gdk_event_queue_append (display, event); _gdk_windowing_got_event (display, node, event, message->base.serial); - - event = gdk_event_new (GDK_FOCUS_CHANGE); - event->focus_change.window = g_object_ref (window); - event->focus_change.in = TRUE; - gdk_event_set_device (event, display->core_pointer); - - node = _gdk_event_queue_append (display, event); - _gdk_windowing_got_event (display, node, event, message->base.serial); } break; case BROADWAY_EVENT_LEAVE: @@ -145,14 +137,6 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message) node = _gdk_event_queue_append (display, event); _gdk_windowing_got_event (display, node, event, message->base.serial); - - event = gdk_event_new (GDK_FOCUS_CHANGE); - event->focus_change.window = g_object_ref (window); - event->focus_change.in = FALSE; - gdk_event_set_device (event, display->core_pointer); - - node = _gdk_event_queue_append (display, event); - _gdk_windowing_got_event (display, node, event, message->base.serial); } break; case BROADWAY_EVENT_POINTER_MOVE: @@ -295,6 +279,19 @@ _gdk_broadway_events_got_input (BroadwayInputMsg *message) _gdk_broadway_screen_size_changed (screen, &message->screen_resize_notify); break; + case BROADWAY_EVENT_FOCUS: + window = g_hash_table_lookup (display_broadway->id_ht, GINT_TO_POINTER (message->focus.id)); + if (window) + { + event = gdk_event_new (GDK_FOCUS_CHANGE); + event->focus_change.window = g_object_ref (window); + event->focus_change.in = TRUE; + gdk_event_set_device (event, display->core_pointer); + node = _gdk_event_queue_append (display, event); + _gdk_windowing_got_event (display, node, event, message->base.serial); + } + break; + default: g_printerr ("_gdk_broadway_events_got_input - Unknown input command %c\n", message->base.type); break; diff --git a/gdk/broadway/gdkwindow-broadway.c b/gdk/broadway/gdkwindow-broadway.c index 8cd060297d..5a67bb15c8 100644 --- a/gdk/broadway/gdkwindow-broadway.c +++ b/gdk/broadway/gdkwindow-broadway.c @@ -537,6 +537,19 @@ static void gdk_broadway_window_focus (GdkWindow *window, guint32 timestamp) { + GdkWindowImplBroadway *impl; + GdkBroadwayDisplay *broadway_display; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window) || + !window->accept_focus) + return; + + impl = GDK_WINDOW_IMPL_BROADWAY (window->impl); + broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window)); + _gdk_broadway_server_window_focus (broadway_display->server, + impl->id); } static void -- 2.30.2